package com.bzkj.document.service.finishedproductentry.impl;


import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.annotation.DataWarehouseScope;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.common.domain.NccRequestDTO;
import com.bzkj.common.enums.DocumentType;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.MessageUtil;
import com.bzkj.common.utils.http.NccHttpUtils;
import com.bzkj.document.domain.DocConfirmDTO;
import com.bzkj.document.domain.finishedproduct.dto.FinishedProductDTO;
import com.bzkj.document.domain.finishedproduct.vo.FinishedProductBodyVo;
import com.bzkj.document.domain.finishedproduct.vo.FinishedProductHeadVo;
import com.bzkj.document.enums.InventoryCheck;
import com.bzkj.document.enums.ProcessingType;
import com.bzkj.document.mapper.FinishedProductInMapper;
import com.bzkj.document.mapper.WmsWareHouseInventoryMapper;
import com.bzkj.document.service.finishedproductentry.FinishedProductEntryService;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.DocumentNoUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import com.bzkj.document.utils.finishedProductin.FinishProductInUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 产成品入库服务层实现类
 * 主要功能包括：
 * 1. 查询NCC产成品入库单
 * 2. 将NCC产成品入库单存入WMS
 * 3. 获取本地已确认的产成品入库单
 * 4. 更新NCC产成品入库单
 */
@Service
public class FinishedProductEntryServiceImpl implements FinishedProductEntryService {

    // 常量定义
    private static final String PK_ORG = "111"; // 固定的组织主键
    private static final String NCC_QUERY_URL = "/nccloud/api/ic/productin/commonquery"; // NCC查询接口URL
    private static final String NCC_UPDATE_URL = "/nccloud/api/ic/productin/update"; // NCC更新接口URL

    // 依赖注入
    @Resource
    private NccHttpUtils nccHttpUtils; // NCC接口请求工具
    @Resource
    private DocumentNoUtils documentNoUtils; // 单据号生成工具
    @Resource
    private FinishedProductInMapper finishedProductInMapper; // 产成品入库单持久层
    @Resource
    private FinishProductInUtils finishProductInUtils; // 产成品入库单工具类
    @Resource
    private MessageUtil messageUtil; // 消息工具类
    @Resource
    private InventoryManagerUtils inventoryManagerUtils; // 库存管理工具类
    @Resource
    private WmsWareHouseInventoryMapper wmsWareHouseInventoryMapper;

    /**
     * 查询NCC产成品入库单
     *
     * @param nccRequestDTO 查询条件
     * @return 分页查询结果
     */
    @Override
    public TableDataInfo selectNccFinishedProductEntry(NccRequestDTO nccRequestDTO) {
        try {
            // 通过仓库进行单据过滤
            nccHttpUtils.setWarehouseId(nccRequestDTO, wmsWareHouseInventoryMapper.selectWarehouseId());
            // 发起NCC查询请求

            NccApiResponse nccApiResponse = nccHttpUtils.post(NCC_QUERY_URL, JSONObject.toJSONString(nccRequestDTO));
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);

            // 解析返回的产成品入库单数据
            List<Map<String, Object>> dataList = finishProductInUtils.parsingFinishProductIns(nccApiResponse, ProcessingType.SELECT_NCC_ORDER.ordinal());

            dataList.removeIf(finishedProductInOrder -> {
                @SuppressWarnings("unchecked")
                Map<String, Object> header = (Map<String, Object>) finishedProductInOrder.get("header");

                String fbillflag = Optional.ofNullable(header)
                        .map(h -> h.get("fbillflag"))
                        .map(Object::toString)
                        .orElse(null);

                String targetFlag = nccRequestDTO.getFbillflag();

                return (targetFlag == null && !"2".equals(fbillflag)) ||
                        (targetFlag != null && !targetFlag.equals(fbillflag));
            });

//            if (dataList == null || dataList.isEmpty()) {
//                throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
//            }

            // 返回分页数据
            return DataProcessUtils.startPageInfo(nccRequestDTO.getPageNum(), nccRequestDTO.getPageSize(), dataList);
        } catch (Exception e) {
            // 处理异常并返回友好提示
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), e, "查询");
            throw new RuntimeException(errorMessage, e);
        }
    }

    /**
     * 将NCC产成品入库单存入WMS
     *
     * @param docConfirmDTO 产成品入库单确认DTO
     * @return 操作结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult insertFinishedProductEntry(DocConfirmDTO docConfirmDTO) {
        // 提取必要信息
        String billDate = nccHttpUtils.getBillDate(docConfirmDTO.getBillDate());

        List<String> billCodeList = docConfirmDTO.getvBillCodeList();
        // 提取确认类型
        int confirmType = docConfirmDTO.getConfirmType() == null ? 1 : docConfirmDTO.getConfirmType();
        // 成功处理的单据列表
        List<String> successList = new ArrayList<>();

        // 处理每个单据
        for (String billCode : billCodeList) {
            // 判断单据是否已存在
            if (isBillExist(billCode)) {
                continue;
            }

            try {
                // 获取并处理产成品入库单
                List<Map<String, Object>> finishProductOrders = fetchFinishProductIns(billCode, billDate);

                // 处理产成品入库单
                String errMsg = processFinishProductIns(finishProductOrders, docConfirmDTO.getLoginUser(), successList, billCode, confirmType);

                // 处理错误信息
                if (errMsg != null) {
                    String[] split = errMsg.split("x-x");
                    if (split.length == 2) {
                        if ("1".equals(split[0])) {
                            throw new RuntimeException(split[1]);
                        } else if ("2".equals(split[0])) {
                            return AjaxResult.wmsApiWarning(split[1]);
                        }
                    }
                }
            } catch (Exception e) {
                String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), e, "确认");
                throw new RuntimeException(exceptionMessage, e);
            }
        }
        return AjaxResult.success(messageUtil.operateSuccessMessage(successList, DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), "确认"));
    }

    /**
     * 检查单据是否已存在
     */
    private boolean isBillExist(String billCode) {
        return finishedProductInMapper.getBillIsExist(billCode) > 0;
    }

    /**
     * 调用 NCC 接口获取产成品入库单数据
     */
    private List<Map<String, Object>> fetchFinishProductIns(String billCode, String billDate) throws Exception {
        // confirmQuery为NCC请求报文
        String confirmQuery = nccHttpUtils.getConfirmQuery(billDate, billCode);
        NccApiResponse nccApiResponse = nccHttpUtils.post(NCC_QUERY_URL, confirmQuery);

        // 校验 NCC 返回结果
        DataProcessCommonUtils.validateNccResponse(nccApiResponse);

        // 解析返回结果
        return finishProductInUtils.parsingFinishProductIns(nccApiResponse, ProcessingType.CONFIRM_ORDER.ordinal());
    }

    /**
     * 处理产成品入库单
     */
    @Transactional(rollbackFor = Exception.class)
    public String processFinishProductIns(List<Map<String, Object>> finishProductIns, LoginUser loginUser,
                                          List<String> successList, String billCode, int confirmType) {
        try {
            for (Map<String, Object> finishProductIn : finishProductIns) {
                // 提取明细数据并校验
                List<Map<String, Object>> detailsList = inventoryManagerUtils.extractDetailsList(finishProductIn, loginUser);
                // 提取表头数据并校验
                Map<String, Object> headerMap = extractHeaderMap(finishProductIn, loginUser);
                // 校验明细数据必填项是否填写
                String validationError = inventoryManagerUtils.checkErrorMsg(detailsList);
                if (validationError != null) {
                    return "1x-x" + validationError;
                }
                // 校验明细行批号
                String batchNoError = inventoryManagerUtils.checkBatchNo(detailsList, confirmType, "warehousein");
                if (batchNoError != null) {
                    return "2x-x" + batchNoError;
                }

                // 判断明细数据库存是否充足并插入数据
                int detailsResult = batchInsertDetails(detailsList, headerMap.get("vtrantypecode").toString());
                billCode = billCode == null ? (String) headerMap.get("vbillcode") : billCode;

                if (detailsResult == detailsList.size()) {
                    // 插入表头数据
                    int headerResult = finishedProductInMapper.addFinishedProductHeader(headerMap);
                    if (headerResult > 0) {
                        NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(NCC_UPDATE_URL, headerMap.get("cgeneralhid").toString(), "ic_finprodin_h", "Y");
                        if (nccApiResponse.isSuccess()) {
                            successList.add(billCode);
                        } else {
                            throw new RuntimeException("向NCC返回同步状态失败，请检查后重试！");
                        }
                    }
                }

//                if (detailsResult == detailsList.size()) {
//                    NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(NCC_UPDATE_URL, headerMap.get("cgeneralhid").toString(), "ic_finprodin_h", "Y");
//                    if (nccApiResponse.isSuccess()) {
//                        successList.add(billCode);
//                    } else {
//                        throw new RuntimeException("向NCC返回同步状态失败，请检查后重试！");
//                    }
//                }
            }
            return null;
        } catch (Exception e) {
            throw new RuntimeException("单据处理失败：" + e.getMessage(), e);
        }
    }

    /**
     * 提取并处理表头数据
     */
    private Map<String, Object> extractHeaderMap(Map<String, Object> finishProductIn, LoginUser loginUser) {
        @SuppressWarnings("unchecked")
        Map<String, Object> headerMap = (Map<String, Object>) finishProductIn.get("header");
        String wmsNo = documentNoUtils.generatePrtOrderNumber();
        headerMap.put("vdef49", wmsNo);
        headerMap.put("vdef50", wmsNo);
        DataProcessUtils.addHeaderInfo(headerMap, loginUser);
        return headerMap;
    }

    /**
     * 提取并处理明细数据
     */
    private List<Map<String, Object>> extractDetailsList(Map<String, Object> materialOutboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> detailsList = (List<Map<String, Object>>) materialOutboundOrder.get("details");
        for (Map<String, Object> detailMap : detailsList) {
            DataProcessUtils.addDetailInfo(detailMap, loginUser);
        }
        return detailsList;
    }

    /**
     * 批量插入明细数据
     */
    @Transactional(rollbackFor = Exception.class)
    public int batchInsertDetails(List<Map<String, Object>> detailsList, String vtrantypecode) {
        AtomicInteger count = new AtomicInteger();
        // 判断库存量是否充足
        boolean inventoryConfirm = inventoryManagerUtils.verifyInventoryConfirm(detailsList, "warehousein", vtrantypecode, DocumentType.FINISHED_PRODUCT_INBOUND.getCode());
        if (inventoryConfirm) {
            detailsList.forEach(detail -> {
                count.addAndGet(finishedProductInMapper.addFinishedProductDetails(detail));
            });
        }
        return count.get();
    }

    private void processNegativeQuantityDetail(String vtrantypecode, Map<String, Object> detail) {
        @SuppressWarnings("unchecked")
        Map<String, Object> cmaterialvid = (Map<String, Object>) detail.get("cmaterialvid");
        String pkMaterial = Optional.ofNullable(cmaterialvid)
                .map(c -> c.get("isMap") != null && (boolean) c.get("isMap") ? c.get("pk").toString() : c.get("value").toString())
                .orElseThrow(() -> new RuntimeException("物料信息缺失！"));

        String vbatchcode = Optional.ofNullable(detail.get("vbatchcode")).map(Object::toString).orElse("");
        double nshouldnum = Double.parseDouble(detail.get("nshouldnum").toString());
        String cstateid = Optional.ofNullable(detail.get("cstateid")).map(Object::toString).orElse("");

        int resultType = inventoryManagerUtils.isEnough("", vtrantypecode, pkMaterial, vbatchcode, nshouldnum, "1", cstateid, "", "");
        if (resultType == InventoryCheck.ENOUGH.ordinal()) {
            if (finishedProductInMapper.addFinishedProductDetails(detail) <= 0) {
                throw new RuntimeException("明细数据插入失败！");
            }
        } else if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
            throw new RuntimeException(cmaterialvid.get("name") + "库存可用量不足！");
        } else if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
            throw new RuntimeException(cmaterialvid.get("name") + "当前商品不支持在此单据类型下使用！");
        }
    }

    /**
     * 获取本地已确认的产成品入库单
     *
     * @param finishedProductDTO 查询条件
     * @param pageNum            当前页码
     * @param pageSize           每页大小
     * @return 分页查询结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DataWarehouseScope(deptAlias = "d", userAlias = "u")
    public TableDataInfo selectFinishedProductEntry(FinishedProductDTO finishedProductDTO, int pageNum, int pageSize) {
        // 处理日期范围
        DataProcessUtils.handleDateRange(finishedProductDTO);

        // 处理单据状态过滤条件
        String originalBillsState = Optional.ofNullable(finishedProductDTO.getBillsState())
                .filter(state -> !state.isEmpty())
                .orElse(null);

        // For header query, we modify state 4/5 to 3
        String headerQueryBillsState = originalBillsState != null
                ? (originalBillsState.equals("4") || originalBillsState.equals("5") ? "3" : originalBillsState)
                : null;
        finishedProductDTO.setBillsState(headerQueryBillsState);

        // 查询表头数据
        List<FinishedProductHeadVo> finishedProductHeadVoList = finishedProductInMapper.queryFinishedProductHeader(finishedProductDTO);

        if (finishedProductHeadVoList.isEmpty()) {
            return DataProcessCommonUtils.getTableInfo(Collections.emptyList(), pageNum, pageSize);
        }

        // 获取物料过滤条件
        String filterMaterialOid = Optional.ofNullable(finishedProductDTO.getMaterial()).orElse("");
        boolean shouldFilterByMaterial = !filterMaterialOid.isEmpty();
        boolean shouldFilterBySkuState = originalBillsState != null
                && (originalBillsState.equals("4") || originalBillsState.equals("5"));

        List<HashMap<String, Object>> responseDataList = finishedProductHeadVoList.parallelStream().map(finishedProductHeadVo -> {
            // 查询对应单据明细
            List<FinishedProductBodyVo> finishedProductBodyVoList = finishedProductInMapper.selectFinishedProductDetails(
                    finishedProductHeadVo.getCgeneralhid(),
                    finishedProductDTO.getBillsState());
            if (finishedProductBodyVoList == null || finishedProductBodyVoList.isEmpty()) {
                return null;
            }
            // 应用过滤条件
            if (shouldFilterByMaterial && finishedProductBodyVoList.stream().noneMatch(body -> filterMaterialOid.equals(body.getCmaterialoid().getPk()))) {
                return null;
            }
            if (shouldFilterBySkuState && finishedProductBodyVoList.stream().noneMatch(body -> originalBillsState.equals(body.getSkuState()))) {
                return null;
            }
            // 构建结果
            HashMap<String, Object> finishedProductMap = new HashMap<>(2);
            finishedProductMap.put("header", finishedProductHeadVo);
            finishedProductMap.put("details", finishedProductBodyVoList);
            return finishedProductMap;
        }).filter(Objects::nonNull).collect(Collectors.toList());

        return DataProcessCommonUtils.getTableInfo(responseDataList, pageNum, pageSize);
    }

    /**
     * 更新NCC产成品入库单
     *
     * @param responseBody 产成品入库单数据
     * @param loginUser    登录用户信息
     * @param isSign       是否跳过校验
     * @return 操作结果
     */
    @Override
    public AjaxResult updateFinishedProductEntry(HashMap<String, Object> responseBody, LoginUser loginUser, boolean isSign) {
        String vbillcode;
        try {
            // 提取并校验头信息
            HashMap<String, Object> headerMap = extractHeaderInfo(responseBody);
            String cgeneralhid = headerMap.get("cgeneralhid").toString();

            // 校验单据状态
            if (!isSign) {
                AjaxResult validationResult = validateBillStatus(cgeneralhid);
                if (!validationResult.isSuccess()) {
                    return validationResult;
                }
            }

            // 封装 NCC 请求参数
            HashMap<String, Object> nccRequestMap = prepareNccRequest(responseBody);
            JSONObject jsonObject = new JSONObject(nccRequestMap);
            JSONObject icFinprodinH = jsonObject.getJSONObject("ic_finprodin_h");
            if (icFinprodinH.get("cwarehouseid") != null) {
                icFinprodinH.remove("cwarehouseid");
            }

            // 调用 NCC 接口并校验返回结果
            NccApiResponse nccApiResponse = nccHttpUtils.post(NCC_UPDATE_URL, jsonObject.toJSONString());
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);
            // 解析和处理返回数据
            List<Map<String, Object>> finishProductIns = finishProductInUtils.parsingFinishProductIns(nccApiResponse, ProcessingType.UPDATE_NCC_ORDER.ordinal());
            vbillcode = processInboundOrders(finishProductIns, loginUser);

        } catch (Exception e) {
            String exceptionMessage;
            if (!isSign) {
                exceptionMessage = messageUtil.operateExceptionMessage(
                        DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), e, "修改"
                );
            } else {
                return AjaxResult.error(messageUtil.operateExceptionMessage(
                        DocumentType.FINISHED_PRODUCT_INBOUND.getCode(), e, "签字"
                ));
            }
            throw new RuntimeException(exceptionMessage, e);
        }

        // 返回成功结果
        return AjaxResult.success(
                messageUtil.operateSuccessMessage(
                        Collections.singletonList(vbillcode),
                        DocumentType.FINISHED_PRODUCT_INBOUND.getCode(),
                        "修改"
                )
        );
    }

    /**
     * 提取头信息并校验
     */
    private HashMap<String, Object> extractHeaderInfo(HashMap<String, Object> responseBody) {
        @SuppressWarnings("unchecked")
        HashMap<String, Object> headerMap = (HashMap<String, Object>) responseBody.get("header");
        if (headerMap == null || !headerMap.containsKey("cgeneralhid")) {
            throw new IllegalArgumentException("提示：单据头信息缺失或不完整！");
        }
        return headerMap;
    }

    /**
     * 校验单据状态
     */
    private AjaxResult validateBillStatus(String cgeneralhid) {
        HashMap<String, String> billInfoMap = finishedProductInMapper.getBillStatus(cgeneralhid);
        String billState = billInfoMap.get("billState");
        return messageUtil.updateBillMessage(billState, DocumentType.FINISHED_PRODUCT_INBOUND.getDescription());
    }

    /**
     * 封装 NCC 请求参数
     */
    private HashMap<String, Object> prepareNccRequest(HashMap<String, Object> responseBody) {
        HashMap<String, Object> nccRequestMap = new HashMap<>(2);
        nccRequestMap.put("ic_finprodin_h", responseBody.get("header"));
        nccRequestMap.put("ic_finprodin_b", responseBody.get("details"));
        return nccRequestMap;
    }

    /**
     * 处理材料出库单
     */
    private String processInboundOrders(List<Map<String, Object>> finishProductIns, LoginUser loginUser) {
        String vbillcode = "";
        for (Map<String, Object> finishProductIn : finishProductIns) {
            @SuppressWarnings("unchecked")
            Map<String, Object> headerInfoMap = (Map<String, Object>) finishProductIn.get("header");
            vbillcode = headerInfoMap.get("vbillcode").toString();
            DataProcessUtils.updateInfo(headerInfoMap, loginUser);

            // 修改表头数据
            int resultNum = finishedProductInMapper.updateFinishedProductHeader(headerInfoMap);
            if (resultNum <= 0) {
                throw new RuntimeException("表头数据更新失败！");
            }

            // 修改表体数据
            @SuppressWarnings("unchecked")
            List<HashMap<String, Object>> detailsList =
                    (List<HashMap<String, Object>>) finishProductIn.get("details");
            int count = updateOrderDetails(detailsList, loginUser);
            if (count != detailsList.size()) {
                String failureMessage = messageUtil.documentFailureMessage(
                        Collections.singletonList(headerInfoMap.get("vbillcode").toString()),
                        DocumentType.FINISHED_PRODUCT_INBOUND.getCode(),
                        "修改",
                        "明细"
                );
                throw new RuntimeException(failureMessage);
            }
        }
        return vbillcode;
    }

    /**
     * 更新表体数据
     */
    private int updateOrderDetails(List<HashMap<String, Object>> detailsList, LoginUser loginUser) {
        int count = 0;
        for (HashMap<String, Object> detailMap : detailsList) {
            DataProcessUtils.updateInfo(detailMap, loginUser);
            count += finishedProductInMapper.updateFinishedProductDetails(detailMap);
        }
        return count;
    }
}
